package com.supreme.threadserver.service;

import com.alibaba.fastjson.JSONObject;
import com.supreme.commonentity.mysql.primary.BizOrder;
import com.supreme.commonmybatis.mapper.AccountMapper;
import com.supreme.commonmybatis.mapper.OrderMapper;
import com.supreme.threadserver.annotation.MingTaskAsync;
import com.supreme.threadserver.annotation.SupremeTaskAsync;
import com.supreme.threadserver.config.ThreadPoolTaskConfig;
import com.supreme.threadserver.handler.ThreadPoolRejectStrategy;
import com.supreme.threadserver.threadpkg.LoopLocalThread;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.concurrent.*;

@Service
public class ThreadPoolService {

    @Resource
    private TaskExecutor taskExecutor;

    @Resource(name = ThreadPoolTaskConfig.SUPREME_TASK_EXECUTOR)
    private TaskExecutor supremeTaskExecutor;

    @Resource
    private ReentryAsyncService reentryAsyncService;

    private ThreadPoolExecutor threadPoolExecutor;

    @Resource
    private AccountMapper accountMapper;

    @Resource
    private OrderMapper orderMapper;

    @PostConstruct
    private void initMyThreadPoolExecutor() {
        int corePoolSize = 2;
        int maximumPoolSize = 4;
        long keepAliveTime = 1000;
        int workQueueSize = 2;
        ArrayBlockingQueue<Runnable> arrayBlockingQueue = new ArrayBlockingQueue<>(workQueueSize);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();

        threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                TimeUnit.MILLISECONDS,
                arrayBlockingQueue,
                threadFactory,
                new ThreadPoolRejectStrategy());
    }

    public void threadPoolAdvanceTest() {
        LoopLocalThread loopLocalThread = new LoopLocalThread(100, 1000);
        final int activeCount = threadPoolExecutor.getActiveCount();
        System.out.println("activeCount: " + activeCount);
        threadPoolExecutor.execute(loopLocalThread);
    }

    public void shutdownNow() {
        threadPoolExecutor.shutdownNow();
    }

    public void supremeTaskExecutor() {
        LoopLocalThread loopLocalThread = new LoopLocalThread(100, 1000);
        supremeTaskExecutor.execute(loopLocalThread);
    }

    public JSONObject printTaskExecutorInfo() {
        final JSONObject returnJsonObject = new JSONObject();

        {
            final JSONObject taskExecutorJson = new JSONObject();

            ThreadPoolTaskExecutor threadPoolTaskExecutor = (ThreadPoolTaskExecutor) taskExecutor;
            final int corePoolSize = threadPoolTaskExecutor.getCorePoolSize();
            taskExecutorJson.put("corePoolSize", corePoolSize);

            final int maxPoolSize = threadPoolTaskExecutor.getMaxPoolSize();
            taskExecutorJson.put("maxPoolSize", maxPoolSize);

            final int poolSize = threadPoolTaskExecutor.getPoolSize();
            taskExecutorJson.put("poolSize", poolSize);

            final int activeCount = threadPoolTaskExecutor.getActiveCount();
            taskExecutorJson.put("activeCount", activeCount);

            final ThreadGroup threadGroup = threadPoolTaskExecutor.getThreadGroup();
            if (threadGroup != null) {
                final String name = threadGroup.getName();
                taskExecutorJson.put("name", name);

                final int maxPriority = threadGroup.getMaxPriority();
                taskExecutorJson.put("maxPriority", maxPriority);
            }

            returnJsonObject.put("taskExecutor", taskExecutorJson);
        }

        {
            final JSONObject supremeTaskExecutorJson = new JSONObject();

            ThreadPoolTaskExecutor threadPoolTaskExecutor = (ThreadPoolTaskExecutor) supremeTaskExecutor;
            final int corePoolSize = threadPoolTaskExecutor.getCorePoolSize();
            supremeTaskExecutorJson.put("corePoolSize", corePoolSize);

            final int maxPoolSize = threadPoolTaskExecutor.getMaxPoolSize();
            supremeTaskExecutorJson.put("maxPoolSize", maxPoolSize);

            final int poolSize = threadPoolTaskExecutor.getPoolSize();
            supremeTaskExecutorJson.put("poolSize", poolSize);

            final int activeCount = threadPoolTaskExecutor.getActiveCount();
            supremeTaskExecutorJson.put("activeCount", activeCount);

            final ThreadGroup threadGroup = threadPoolTaskExecutor.getThreadGroup();
            if (threadGroup != null) {
                final String name = threadGroup.getName();
                supremeTaskExecutorJson.put("name", name);

                final int maxPriority = threadGroup.getMaxPriority();
                supremeTaskExecutorJson.put("maxPriority", maxPriority);
            }

            returnJsonObject.put("supremeTaskExecutor", supremeTaskExecutorJson);
        }

        return returnJsonObject;
    }

    @Async(value = ThreadPoolTaskConfig.TASK_EXECUTOR)
    public void asyncTaskExecutor() {
        final Thread currentThread = Thread.currentThread();
        for (int i = 0; i < 100; i++) {
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
                System.out.printf("[NAME: %s ID: %d]\n", currentThread.getName(), currentThread.getId());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Async(value = ThreadPoolTaskConfig.SUPREME_TASK_EXECUTOR)
    public void asyncSupremeTaskExecutor() {
        final Thread currentThread = Thread.currentThread();
        for (int i = 0; i < 100; i++) {
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
                System.out.printf("[NAME: %s ID: %d]\n", currentThread.getName(), currentThread.getId());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @SupremeTaskAsync
    public void reentryThreadDemo() {
        String threadName = Thread.currentThread().getName();
        System.out.println("ThreadPoolService reentryThreadDemo threadName = " + threadName);
        reentryAsyncService.reentryThreadDemo();
    }

    @MingTaskAsync
    public void insertBatchAccount(int index) {
        Thread thread = Thread.currentThread();
        BizOrder bizOrder = new BizOrder().setOrderType(1)
                .setOrderNum(index)
                .setOrderCode(thread.getName());
        orderMapper.insert(bizOrder);
    }
}
